package mango.orm;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;

import mango.functions.FuncDate;
import mango.functions.FuncString;



public final class OrmTypes {
    @SuppressWarnings("unused")
    private static final Class<?>[] SUPPORTED_JAVA_TYPE = new Class<?>[]{
        byte.class,
        short.class,
        int.class,
        long.class,
        float.class,
        double.class,
        boolean.class,
        Byte.class,
        Short.class,
        Integer.class,
        Long.class,
        Float.class,
        Double.class,
        Boolean.class,
        BigDecimal.class,
        String.class,
        Date.class,
        InputStream.class,
        Object.class
    };
    
    @SuppressWarnings("unused")
    private static final int[] SUPPORTED_JDBC_TYPE = new int[]{
        java.sql.Types.CHAR,
        java.sql.Types.VARCHAR,
        -9,//java.sql.Types.NVARCHAR,
        java.sql.Types.LONGVARCHAR,
        -16,//java.sql.Types.LONGNVARCHAR,
        java.sql.Types.INTEGER,
        java.sql.Types.NULL,
        java.sql.Types.NUMERIC,
        java.sql.Types.REAL,
        java.sql.Types.BIGINT,
        java.sql.Types.DATE,
        java.sql.Types.TIMESTAMP,
        java.sql.Types.CLOB,
        2011,//java.sql.Types.NCLOB,
        java.sql.Types.BLOB,
        java.sql.Types.SMALLINT
    };
    
    private static final HashMap<String, String> JDBC_NAME_MAP = new HashMap<String, String>();
    
    static {
        JDBC_NAME_MAP.put("VARCHAR", "Types.VARCHAR");
        JDBC_NAME_MAP.put("VARCHAR2", "Types.VARCHAR");
        JDBC_NAME_MAP.put("NVARCHAR2", "Types.VARCHAR");
        JDBC_NAME_MAP.put("CHAR", "Types.CHAR");
        JDBC_NAME_MAP.put("NCHAR", "Types.CHAR");
        JDBC_NAME_MAP.put("NUMBER", "Types.DOUBLE");
        JDBC_NAME_MAP.put("NUMERIC", "Types.DOUBLE");
        JDBC_NAME_MAP.put("DECIMAL", "Types.DOUBLE");
        JDBC_NAME_MAP.put("FLOAT", "Types.DOUBLE");
        JDBC_NAME_MAP.put("INTEGER", "Types.INTEGER");
        JDBC_NAME_MAP.put("DATE", "Types.DATE");
        JDBC_NAME_MAP.put("DATETIME", "Types.DATE");
        JDBC_NAME_MAP.put("TIMESTAMP", "Types.TIMESTAMP");
        JDBC_NAME_MAP.put("CLOB", "Types.CLOB");
        JDBC_NAME_MAP.put("TEXT", "Types.CLOB");
        JDBC_NAME_MAP.put("BLOB", "Types.BLOB");
        JDBC_NAME_MAP.put("SMALLINT", "Types.SMALLINT");
        JDBC_NAME_MAP.put("INT", "Types.SMALLINT");
        JDBC_NAME_MAP.put("LONG", "Types.LONGVARCHAR");
    }
    
    private static final String pFunc1(String jdbcName, String length, String precision) {
        String type = jdbcName;
        if (FuncString.isBlank(jdbcName)) {
            throw new TypesException("数据类型 " + jdbcName + " 错误");
        }
        if (jdbcName.indexOf("(") > 0) {
            type = jdbcName.substring(0, jdbcName.indexOf("("));
        }
        type = type.toUpperCase();

        if ("NUMBER".equals(type)) {
            if (length != null && FuncString.isBlank(precision)) {
                type = "INTEGER";
            }
        }
        return type;
    }
    
    public static final String func1(String jdbcName, String length, String precision) {
        String jdbcType = JDBC_NAME_MAP.get(pFunc1(jdbcName, length, precision));
        if (jdbcType == null) {
            throw new TypesException("不支持的数据类型 : " + jdbcName);
        }
        return jdbcType;
    }
    
    private static final HashMap<String, String> JDBC_JAVA_NAME_MAP = new HashMap<String, String>();
    
    static {
        JDBC_JAVA_NAME_MAP.put("VARCHAR", "String");
        JDBC_JAVA_NAME_MAP.put("VARCHAR2", "String");
        JDBC_JAVA_NAME_MAP.put("NVARCHAR2", "String");
        JDBC_JAVA_NAME_MAP.put("CHAR", "String");
        JDBC_JAVA_NAME_MAP.put("NCHAR", "String");
        JDBC_JAVA_NAME_MAP.put("NUMBER", "Double");
        JDBC_JAVA_NAME_MAP.put("NUMERIC", "Double");
        JDBC_JAVA_NAME_MAP.put("DECIMAL", "Double");
        JDBC_JAVA_NAME_MAP.put("FLOAT", "Double");
        JDBC_JAVA_NAME_MAP.put("INTEGER", "Integer");
        JDBC_JAVA_NAME_MAP.put("DATE", "java.util.Date");
        JDBC_JAVA_NAME_MAP.put("DATETIME", "java.util.Date");
        JDBC_JAVA_NAME_MAP.put("TIMESTAMP", "java.util.Date");
        JDBC_JAVA_NAME_MAP.put("CLOB", "String");
        JDBC_JAVA_NAME_MAP.put("TEXT", "String");
        JDBC_JAVA_NAME_MAP.put("BLOB", "java.io.InputStream");
        JDBC_JAVA_NAME_MAP.put("SMALLINT", "Integer");
        JDBC_JAVA_NAME_MAP.put("INT", "Integer");
        JDBC_JAVA_NAME_MAP.put("LONG", "String");
    }
    
    public static final String func2(String jdbcName, String length, String precision) {
        String javaType = JDBC_JAVA_NAME_MAP.get(pFunc1(jdbcName, length, precision));
        if (javaType == null) {
            throw new TypesException("不支持的数据类型 " + jdbcName);
        }
        return javaType;
    }
    
    
    private static final HashMap<String, String> RESULTSET_READ_JAVATYPE = new HashMap<String, String>();
    
    static {
        RESULTSET_READ_JAVATYPE.put(byte.class.getName(), "getByte");
        RESULTSET_READ_JAVATYPE.put(short.class.getName(), "getShort");
        RESULTSET_READ_JAVATYPE.put(int.class.getName(), "getInt");
        RESULTSET_READ_JAVATYPE.put(long.class.getName(), "getLong");
        RESULTSET_READ_JAVATYPE.put(double.class.getName(), "getDouble");
        RESULTSET_READ_JAVATYPE.put(boolean.class.getName(),  "getBoolean");
        RESULTSET_READ_JAVATYPE.put(java.lang.Byte.class.getName(), "getByte");
        RESULTSET_READ_JAVATYPE.put(java.lang.Short.class.getName(), "getShort");
        RESULTSET_READ_JAVATYPE.put(java.lang.Integer.class.getName(), "getInt");
        RESULTSET_READ_JAVATYPE.put(java.lang.Long.class.getName(), "getLong");
        RESULTSET_READ_JAVATYPE.put(java.lang.Double.class.getName(), "getDouble");
        RESULTSET_READ_JAVATYPE.put(java.lang.Boolean.class.getName(),  "getBoolean");
        RESULTSET_READ_JAVATYPE.put(java.math.BigDecimal.class.getName(),  "getBigDecimal");
        RESULTSET_READ_JAVATYPE.put(java.lang.String.class.getName(), "getString");
        RESULTSET_READ_JAVATYPE.put(java.util.Date.class.getName(), "getDate");
        RESULTSET_READ_JAVATYPE.put(InputStream.class.getName(), "getBinaryStream");
    }
    
    public static String func3(Class<?> clazz) {
        String method = RESULTSET_READ_JAVATYPE.get(clazz.getName());
        if (FuncString.isBlank(method)) {
            throw new TypesException("不支持的Java类型 : " + clazz.getName());
        }
        return method;
    }
    
    @SuppressWarnings("unchecked")
    public static <E>E convert(Class<E> clazz, Object obj) {
        try {
            if (obj == null || FuncString.isBlank(String.valueOf(obj))) {
                if (clazz.isPrimitive()) {
                    return (E) Byte.valueOf("0");
                }
                else {
                    return null;
                }
            }
            else if (clazz.isArray() || obj.getClass().isArray()) {
                throw new TypesException("不支持数组类型的转换");
            }
            else if (byte.class == clazz || Byte.class == clazz) {
                return (E) Byte.valueOf(String.valueOf(obj));
            }
            else if (int.class == clazz || Integer.class == clazz) {
                return (E) Integer.valueOf(String.valueOf(obj));
            }
            else if (long.class == clazz || Long.class == clazz) {
                return (E) Long.valueOf(String.valueOf(obj));
            }
            else if (double.class == clazz || Double.class == clazz) {
                return (E) Double.valueOf(String.valueOf(obj));
            }
            else if (boolean.class == clazz || Boolean.class == clazz) {
                if ("TRUE".equalsIgnoreCase(String.valueOf(obj)) || "1".equalsIgnoreCase(String.valueOf(obj))) {
                    return (E) Boolean.valueOf(true);
                }
                return (E) Boolean.valueOf(false);
            }
            else if (Date.class == clazz) {
                if (obj instanceof java.util.Date) {
                    return (E)obj;
                }
                else {
                    return (E) FuncDate.toDate(String.valueOf(obj));
                }
            }
            else if (String.class == clazz) {
                return (E) String.valueOf(obj);
            }
            else if (InputStream.class == clazz) {
                if (obj instanceof InputStream) {
                    return (E)obj;
                }
                else {
                    throw new TypesException("无法将 " + obj.getClass().getName() + " 转换为 java.io.InputStream");
                }
            }
            else {
                throw new TypesException("不支持的数据转换类型：" + clazz.getName());
            }
        }
        catch(Exception e) {
            if (e instanceof TypesException) {
                throw (TypesException)e;
            }
            else {
                throw new TypesException("无法将 " + obj.getClass().getName() + " 类型转换为 " + clazz.getName());
            }
        }
    }
}
